/**
*
*	Grain.cpp
*
**/


#include "ADSR.h"
//#include "RtWvOut.h" //quizá para callback RtAudio.h
#include "RtAudio.h"
#include "SineWave.h"

using namespace stk;

class Grain{
	public:
		Grain(StkFloat frequency);
		~Grain(void);
		void init(StkFloat frequency);
		void keyOn(void);
		void setBaseFrequency(StkFloat frequency);
		void setTremuloFrequency(StkFloat frequency);
		void setVibratoFrequency(StkFloat frequency);
		StkFloat tick();
	
	
	protected:
		SineWave vibrato_;	//carrier
		SineWave modulating_;
		SineWave tremulo_;
		ADSR enveloping_FM_;
		ADSR enveloping_out_;
		//StkFrames signal_;
		StkFloat base_frequency_;
		
};

Grain::Grain( StkFloat frequency ){
	init(frequency);
}

Grain::~Grain( void ){
}

void Grain::init(StkFloat frequency){
	setBaseFrequency(frequency);
	setVibratoFrequency(1.0);
	setTremuloFrequency(10.0);
	enveloping_FM_.setAllTimes(5, 0.003, 1.0, 0.01); //desde STK_BeeThree.cpp
	enveloping_out_.setAllTimes(10, 0.003, 1.0, 0.01);
}

void Grain::keyOn(void){
	enveloping_FM_.keyOn();
	enveloping_out_.keyOn();
	}

void Grain::setBaseFrequency(StkFloat frequency){ 
	base_frequency_ = frequency;
	}
void Grain::setVibratoFrequency(StkFloat frequency){
	vibrato_.setFrequency(frequency);
	}
void Grain::setTremuloFrequency(StkFloat frequency){
	tremulo_.setFrequency(frequency);
	}

StkFloat Grain::tick(){
	StkFloat temp;
	StkFloat temp2;
	temp = 1 + vibrato_.tick();
	temp2 = 1 + tremulo_.tick();
	modulating_.setFrequency(base_frequency_*temp);
	temp = modulating_.tick()*enveloping_FM_.tick();
	temp = (temp*temp2)/2.0;
	temp = temp*enveloping_out_.tick();
	return temp;
	}


//REALTIME CALLBACK
/**
 * This tick() function handles sample computation only. It will be 
 * called automatically when the system needs a new buffer of audio 
 * samples.
 **/

int tick(void *outputBuffer, void *inputBuffer, unsigned int nBufferFrames, 
double streamTime, RtAudioStreamStatus status, void *dataPointer){
		
		Grain *grano = (Grain *)dataPointer;
		register StkFloat *samples = (StkFloat *) outputBuffer;
		for(unsigned int i = 0;i<nBufferFrames;i++)
				*samples ++ = grano->tick();
		return 0;
}

int main(){
	Stk::setSampleRate(44100.0);
	
	Grain grano(440.0);
	//FileLoop input("/home/daviciyo/stk/rawwaves/sinewave.raw",true);
	RtAudio dac;
	
	//Figure out how many bytes in an StkFloat and setup the RtAudio 
	//stream
	
	RtAudio::StreamParameters parameters;
	parameters.deviceId = dac.getDefaultOutputDevice();
	parameters.nChannels = 1;
	RtAudioFormat format = (sizeof(StkFloat) == 8) ? RTAUDIO_FLOAT64 : 
	RTAUDIO_FLOAT32;
	unsigned int bufferFrames = RT_BUFFER_SIZE;
	try{
		dac.openStream( &parameters, NULL, format, (unsigned int)Stk::sampleRate(), &bufferFrames, &tick, (void *)&grano);
		
	}catch(RtError &error){ 
		error.printMessage(); 
		goto cleanup;
	}
	
grano.setVibratoFrequency(10.0);
grano.setTremuloFrequency(500.0);
	grano.keyOn();
	
	
	try{
		dac.startStream();
	} catch(RtError &error){
		error.printMessage();
		goto cleanup;
	}
	
	//Block waiting here
	
	char keyhit;
	
	std::cout<<"\n Playing.... press <enter> to quit.\n";
	std::cin.get(keyhit);
	//shut down the output stream
	
	try{
		dac.closeStream();
	}
	catch(RtError &error){
		error.printMessage();
	}
	
	cleanup:
		return 0;

}



//MAIN PARA RTBLOCKING

/*
int main(){
	
	Stk::setSampleRate(44100.0);
	Stk::showWarnings(true);
	
	RtWvOut * dac;
	Grain grano(440.0);
	grano.setTremuloFrequency(5000.0);
	grano.setVibratoFrequency(20.0);
	StkFloat nFrames = 500000;
	
	try{
		dac = new RtWvOut(1);
		}catch(StkError &){exit(1);}
	
	for(int i = 0;i<nFrames;i++){
		try{
			dac->tick(grano.tick());
		}catch(StkError &){goto cleanup;}
	}
	
	cleanup:
		delete dac;
		
	
return 0;
}*/
